package com.ikas.ai.server.module.instance.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikas.ai.server.module.instance.dao.WorkInstanceStepCostDao;
import com.ikas.ai.server.module.instance.model.WorkFlowInstance;
import com.ikas.ai.server.module.instance.model.WorkInstanceStep;
import com.ikas.ai.server.module.instance.model.WorkInstanceStepCost;
import com.ikas.ai.utils.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WorkInstanceStepCostService extends ServiceImpl<WorkInstanceStepCostDao, WorkInstanceStepCost> {

    @Autowired
    WorkInstanceStepService workInstanceStepService;
    @Autowired
    WorkFlowInstanceService workFlowInstanceService;


    @Value("${work-instance.step.delay.max-length:100}")
    Integer maxStepDelayLength;

    /**
     * @param machineNo
     * @param step
     */
    @Transactional(rollbackFor = Exception.class)
    public void computeAvgDelay(String machineNo, WorkInstanceStep step) {
        if (machineNo == null) {
            return;
        }
        WorkInstanceStepCost one = getOne(
                new LambdaQueryWrapper<WorkInstanceStepCost>()
                        .eq(WorkInstanceStepCost::getMachineNo, machineNo)
                        .eq(WorkInstanceStepCost::getWfName, step.getWfName())
                        .eq(WorkInstanceStepCost::getStepName, step.getStepName())
        );
        //如果为空，新建一个对象，并新建一个数组并放入当前delay时间
        if (one == null) {
            one = new WorkInstanceStepCost().setMachineNo(machineNo).setWfName(step.getWfName()).setStepName(step.getStepName()).setMeteCode(step.getMeteCode());
            List<Long> delayArray = new ArrayList<>();
            delayArray.add(step.getDelay());
            one.setDelayArray(delayArray);
            one.setAvgDelay(step.getDelay());
        } else {
            one = dealWithDelay(step.getDelay(), one);
            one.setUpdateTime(new Date());
        }
        save(one);
        //更新step表avgTime
        step.setAvgDelay(one.getAvgDelay());
        step.setUpdateTime(new Date());
        workInstanceStepService.updateById(step);
    }

    private WorkInstanceStepCost dealWithDelay(Long costTime, WorkInstanceStepCost one) {
        if (costTime == null) {
            return one;
        }
        if (one.getDelayArray() == null) {
            one.setDelayArray(new ArrayList<>());
        }
        LinkedList<Long> delayArray = new LinkedList<>(one.getDelayArray());
        if (delayArray.size() < maxStepDelayLength) {
            //DO NOTHING
            delayArray.addFirst(costTime);
        } else if (delayArray.size() > maxStepDelayLength) {
            Integer defaultSize = delayArray.size();
            for (int k = 0; k <= defaultSize - maxStepDelayLength; k++) {
                delayArray.pollLast();
            }
            delayArray.addFirst(costTime);
        } else {
            delayArray.removeLast();
            delayArray.addFirst(costTime);
        }
        one.setDelayArray(delayArray);
        Long sum = 0L;
        for (Long delayElement : delayArray) {
            sum += delayElement;
        }
        Long avgDelay = 0L;
        if (sum != 0) {
            avgDelay = sum / delayArray.size();
        }
        one.setAvgDelay(avgDelay);
        return one;
    }

    public void putExistStepDelayIntoTable() {
        List<WorkFlowInstance> workFlowInstances = workFlowInstanceService.list();
        Map<Long, String> machineNoCollect = workFlowInstances.stream().collect(Collectors.toMap(
                WorkFlowInstance::getId,
                WorkFlowInstance::getMachineNo
        ));
        List<WorkInstanceStep> stepList = workInstanceStepService.list();
        Map<Long, List<WorkInstanceStep>> stepCollect = stepList.stream().collect(Collectors.groupingBy(WorkInstanceStep::getStepId));
        log.info("=---开始初始化，共有WorkInstanceStep {} 个,属于 {} 个Condition--=", stepList.size(), stepCollect.keySet().size());
        Integer countFlag = 0;
        List<WorkInstanceStepCost> stepCosts = new ArrayList<>();
        for (Long stepConditionId : stepCollect.keySet()) {
            countFlag += 1;
            log.info("===============>开始处理第{}个=================>", countFlag);
            List<WorkInstanceStep> workInstanceSteps = stepCollect.get(stepConditionId);
            if (CollectionUtil.isEmpty(workInstanceSteps)) {
                continue;
            }
            WorkInstanceStepCost workInstanceStepCost = new WorkInstanceStepCost();
            WorkInstanceStep workInstanceStep = workInstanceSteps.get(0);
            String machineNo = machineNoCollect.get(workInstanceStep.getWfInstanceId());
            if (machineNo == null) {
                continue;
            }
            String wfName = workInstanceStep.getWfName();
            String stepName = workInstanceStep.getStepName();
            String meteCode = workInstanceStep.getMeteCode();
            workInstanceStepCost.setStepName(stepName).setWfName(wfName).setMachineNo(machineNo).setMeteCode(meteCode);
            log.info("=-----开始处理工况{}，步骤名为{}的步骤，下属步骤实例{}个----=", wfName, stepName, workInstanceSteps.size());
            List<Long> delayArray = new ArrayList<>();
            Long sum = 0L;
            for (WorkInstanceStep stepElement : workInstanceSteps) {
                if (delayArray.size() <= maxStepDelayLength) {
                    Long delay = stepElement.getDelay();
                    if (delay == null) {
                        continue;
                    }
                    delayArray.add(delay);
                    sum += delay;
                } else {
                    break;
                }
            }
            Long avgDelay = 0L;
            if (sum != 0L) {
                avgDelay = sum / delayArray.size();
            }
            workInstanceStepCost.setAvgDelay(avgDelay);
            workInstanceStepCost.setDelayArray(delayArray);
            log.info("=-----最终结果，平均时间为：{},整体数组为：{}----=", avgDelay, delayArray);
            stepCosts.add(workInstanceStepCost);
        }
        stepCosts = stepCosts.stream().filter(bean -> bean.getMeteCode() != null).distinct().collect(Collectors.toList());
        saveBatch(stepCosts);
    }
}
